<html>
<head>
	<meta charste="utf-8">

	<title>Nonocrams 数织</title>
	
	<style>
		.mainPanel{
			font-size: 12px;
		}
		.headPanel{
			padding: 12px; border-bottom: 1px solid gray; background: #EEE;
		}
		.headPanel h2{
			color: #FFF; 
			text-shadow: 0 1px 0 #ccc, 
				0 2px 0 #c9c9c9, 
				0 3px 0 #bbb, 
				0 4px 0 #b9b9b9, 
				0 5px 0 #aaa, 
				0 6px 1px rgba(0,0,0,.1), 
				0 0 5px rgba(0,0,0,.1), 
				0 1px 3px rgba(0,0,0,.3), 
				0 3px 5px rgba(0,0,0,.2), 
				0 5px 10px rgba(0,0,0,.25), 
				0 10px 10px rgba(0,0,0,.2), 
				0 20px 20px rgba(0,0,0,.15); 
		}
		.footerPanel{
			padding: 12px; border-top: 1px solid gray;
		}
		.gamePanel{
			width: 100%; margin: 15px; cursor: default;
		}
		.gameUIPanel{
			margin: 0 auto; padding: 12px; border: 1px solid black; border-radius:15px; box-shadow: 4px 3px 2px #999;
		}
		
		/* 游戏元素样式 */
		.gameUIRowPanel{ }
		.gameUIRowPanel div{
			width: 15px; height: 15px; position: relative; user-select: none; border-radius:3px;
		}
		
		.gameCellN{ border: 1px solid #FFF; background: #FFF;}
		
		.gameCellD{ border: 1px solid #6C6C6C; background: #FFF;}
		.gameCellDE{ border: 1px solid #6C6C6C;} 
		.gameCellDE:before{ content: "X"; display:block; margin: 1px 0 0 1px; width: 13px; height: 13px; background: #F00; color: #FFF; } 
		
		.gameCellDS{ border: 1px solid #6C6C6C;}
		.gameCellDS:before{ content: " "; display:block; margin: 1px 0 0 1px; width: 13px; height: 13px; background: #F60; }
		
		.gameCellDM{ border: 1px solid #6C6C6C; }
		.gameCellDM:before{  content: "X"; display:block; margin: 1px 0 0 1px; width: 13px; height: 13px; color: #F00; font-weight: bold; }
		
		.gameCellT{ border: 1px dashed #BEBEBE; background: #FFF; color: #333; font-weight: bold; }
		.gameCellTS{ border: 1px dashed #BEBEBE; background: #FFF; color: #F60; font-weight: bold; }
		
		/* 游戏生命数-红心 */
		.gameHeart{
			width:20px; height:25px; position:relative;
		}
		.gameHeart:before{
			content:" "; width:10px; height:15px; position:absolute;
			
			border: 0 solid transparent;  
			border-radius:25px 25px 0 0;
			background:red;
			transform: rotate(-45deg); 
			left:5px;
		}
		.gameHeart:after{
			content:" "; width:10px; height:15px; position:absolute; box-shadow: 3px 0px 0 #999;
			
			border: 0 solid transparent;  
			border-radius:25px 25px 0 0; 
			background:red;
			transform: rotate(45deg);  
			left:8px;
			top:0px;
		}
		
	</style>
	<script>
		var gameModes = {
			//  手动校验          实时校验
			Manual: "Manual", RealTime: "RealTime"
		};
		
		var lifeTime = 3; // 实时模式下的生命次数(3+游戏尺寸)
		var currGameModel = gameModes.RealTime; // 当前游戏模式
		
		function initNonocrams(size){
			let xlen = 0;
			let ylen = 0;
			let gameMaps = initNonocramsDataMap(size);
			
			xlen = gameMaps[0].length;
			ylen = gameMaps.length;
						
			initGameUI(gameMaps, xlen, ylen);
		}
		
		// 初始化游戏UI
		function initGameUI(gameMaps, xlen, ylen){
			gameUIPanel.innerHTML = "";
			gameUIPanel.style.width = xlen*17;
			gameUIPanel.style.height = ylen*17;
			
			// 游戏状态
			gameUIPanel.setAttribute("gameState", "");
			
			for(let y=0; y<ylen; y++){
				// 创建行
				let row = document.createElement('div');
				row.id = `"GameRow-${y}`;
				row.className = "gameUIRowPanel";
				
				row.style.width = xlen*17 + xlen;
				row.style.height = 17; 
				
				row.style.marginTop = y == 0 ? ylen/2 : 0;
				row.style.marginLeft = xlen/2; 
				
				// 渲染行
				gameUIPanel.appendChild(row);
				
				// 创建单元格
				for(let x=0; x<xlen; x++){
					let did = `GameCell-${y}-${x}`;
					let cell = document.createElement('div');
					cell.id = did;
					cell.unselectable = "on";
					
					cell.style.top = -x*17-y;
					cell.style.left = x*17-x; 
					
					// 自定义属性 设置数据 
					let tarr = gameMaps[y][x].split("-");
					let tarr0 = tarr[0] == "L" || tarr[0] == "T" ? "T" : tarr[0];
					let tarr1 = tarr[1];
					
					// 设置初始化的样式
					cell.className = "gameCell" + tarr0;
					
					cell.setAttribute("gameCellType", tarr0);
					cell.setAttribute("gameCellData", tarr1);
					cell.setAttribute("gameCellChange", 0);
					
					// 显示提示信息
					cell.innerHTML = tarr0 == "T" && tarr1 != "N" ? tarr1 : " ";
					
					// 绑定事件
					cell.addEventListener('click', gameCellClickEvent, false);
					cell.addEventListener('contextmenu', gameCellContextmenuEvent, false);
					
					row.appendChild(cell);
				}
			} 
			
			initHeart(); // 初始化生命数
			initAuxiliaryLine(); // 初始化辅助线
		}
		
		// 初始化游戏红心
		function initHeart(){
			// 生成生命数面板
			let heartPanel = document.createElement('div');
				heartPanel.id = 'GameHeartPanel';
				heartPanel.style.marginTop = -10 - parseInt(gameUIPanel.style.height.replace("px", ""));
				heartPanel.style.marginLeft = 20 + parseInt(gameUIPanel.style.width.replace("px", ""));
			
				// 如果不是实时模式就不需渲染红心了
				heartPanel.style.display = currGameModel == gameModes.RealTime ? "" : "none";
			
			// 渲染元素
			gameUIPanel.appendChild(heartPanel);
			
			// 填充心
			let size = document.querySelector("[name='gamesize']:checked").value;
				size = parseInt(size) + 2;
			for(let i=0; i<size; i++){
				let heart = document.createElement('div');
				heart.id = `GameHeart-${i}`;
				heart.className = "gameHeart";
				
				heartPanel.appendChild(heart);
			}
		}
		
		// 初始化辅助线
		function initAuxiliaryLine(){
			// 填充心
			let size = document.querySelector("[name='gamesize']:checked").value;
				size = parseInt(size) - 1;
			
			if(size > 0){
				let nrs = 0;
				let rds = document.querySelectorAll(".gameUIRowPanel");
				for(let i=0; i<rds.length; i++){
					let row = rds[i];
					
					if(row.firstElementChild.getAttribute("gameCellType") == "N"){
						nrs++;
						continue;
					}
					
					// 当前行号
					let crn = i-nrs;
					// 获取指定子元素
					let cds = row.querySelectorAll(".gameCellD");
					for(let j=0; j<cds.length; j++){
						// 纵线
						if(j>0 && j%5 == 0){
							cds[j].style.borderLeft = "1px solid #000";
						}
						// 横线
						if(crn>1 && crn%5 == 0){
							cds[j].style.borderTop = "1px solid #000";
						}
					} 
				}
			}
		}
		
		// 游戏的单击事件
		function gameCellClickEvent(e){
			let dom = e.target;
			let change = dom.getAttribute("gameCellChange");
			
			// 检测是否可以单击
			if(!gameCellHandle(e)){ return; }
			
			dom.setAttribute("gameCellChange", change == "1" ? "0" : "1");
		}
		// 游戏的右击事件
		function gameCellContextmenuEvent(e){ 
			// 事件内容的具体处理
			gameCellHandle(e);
			
			// 阻止默认的右击事件
			e.returnValue = false;
			return false;
		}
		// 游戏左右点击事件处理
		function gameCellHandle(e){
			let dom = e.target;
			let type = dom.getAttribute("gameCellType");
			let data = dom.getAttribute("gameCellData");
			let change = dom.getAttribute("gameCellChange");
			
			// 检查游戏是否结束
			if(gameUIPanel.getAttribute("gameState")){
				return false;
			}
			
			// 当前样式
			let cname = dom.className;
			if(e.type == "click"){
				// 游戏模式
				if(currGameModel == gameModes.RealTime){
					if(type == "D"){
						// 当处于错误/标记状态时, 不响应单击事件
						if(cname == "gameCellDE" || cname == "gameCellDM"){
							return false;
						}else if(cname == "gameCellD"){
							cname = data == "0" ? "gameCellDE" : "gameCellDS";
						}else{
							// cname = "gameCellD";
						}
					}else if(type == "T"){ }else{ } // 提示区域和空白区域无需触发事件
			
					// 更换样式
					dom.className = cname; 
					
					// 检测是否完成游戏
					if(type == "D" && cname == "gameCellDS"){
						let snum = document.querySelectorAll(".gameCellDS").length;
						let maxnum = document.querySelectorAll("div[gamecelltype='D'][gamecelldata='1']").length;
						
						if(snum == maxnum){
							let tds = document.querySelectorAll(".gameCellD[gamecelltype='D'][gamecelldata='0']");
							for(let i=0; i<tds.length; i++){
								tds[i].className = "gameCellDM";
							}
							
							// 设置状态
							gameUIPanel.setAttribute("gameState", "finish"); 
							alert("恭喜你, 游戏结束...");
						}
						
						return true;
					}
					
					// 检测是否单击错误
					if(type == "D" && cname == "gameCellDE"){
						// 去掉一个生命
						GameHeartPanel.removeChild(GameHeartPanel.lastChild);
						
						// 判断剩余生命数
						if(GameHeartPanel.children.length == 0){
							// 设置状态
							gameUIPanel.setAttribute("gameState", "fail");
							alert("很遗憾, 游戏结束...");
						}
						
						return false;
					}
				}else{
					// 手动模式暂未实现
				}
			}else if(e.type == "contextmenu"){
				// 如果已经单击了, 就不能再响应右击事件了
				if(dom.className == "gameCellDM"){
					dom.className = "gameCellD";
				}else if(dom.className == "gameCellD"){
					dom.className = "gameCellDM";
				}else{
					// 其他样式不响应
				}
			}else{
				// 暂无要处理的事件
			} 
			
			return true;
		}
		
		// 初始化游戏数据
		function initNonocramsDataMap(size){
			// 游戏数据地图
			let gameDataMaps = [];
			// 游戏数据地图最大尺寸
			let gameDataSize = size*5;
			 
			// 初始化元素
			for(let ridx=0; ridx<gameDataSize; ridx++){
				gameDataMaps[ridx] = [];
				for(let cidx=0; cidx<gameDataSize; cidx++){
					gameDataMaps[ridx][cidx] = parseInt(Math.random()*10)%2;
				}
			}
			
			// 初始化 列提示信息 
			let leftGameTooltip = extractGameTooltip(gameDataMaps);
			
			// 初始化 行提示信息
			let _t1 = row2column(gameDataMaps);  
			let _t2 = extractGameTooltip(_t1); 
			let topGameTooltip = row2column(_t2);
			
			// 融合成一个大集合 
			let gameMaps = [];
			let tooltipHSize = topGameTooltip.length;    // 提示信息高度
			let tooltipWSize = leftGameTooltip[0].length; // 提示信息宽度
			let tooltipWMaxSize = gameDataSize + tooltipWSize; // 最大宽度
			let tooltipHMaxSize = gameDataSize + tooltipHSize; // 最大高度
			
			for(let ridx=0; ridx<tooltipHMaxSize; ridx++){
				gameMaps[ridx] = [];
				
				for(let cidx=0; cidx<tooltipWMaxSize; cidx++){
					try{
						// 判断要填充地图数据
						if(ridx < tooltipHSize && cidx >= tooltipWSize){ // 行提示
							gameMaps[ridx].push("T-"+topGameTooltip[ridx][cidx-tooltipWSize]); 
						}else if(ridx >= tooltipHSize && cidx < tooltipWSize){ // 列提示
							gameMaps[ridx].push("L-"+leftGameTooltip[ridx-tooltipHSize][cidx]); 
						}else if(ridx >= tooltipHSize && cidx >= tooltipWSize){ // 填充数据
							gameMaps[ridx].push("D-"+gameDataMaps[ridx-tooltipHSize][cidx-tooltipWSize]); 
						}else{
							gameMaps[ridx].push("N-N");
						}
					}catch(e){
						console.error(e.message);
					}
				}
			} 
			
			return gameMaps;
		}
		
		// 获取二维数组的一列 [局限于正方形二维数组]
		function row2column(oarr){
			let narr = [];
			
			for(let x=0; x<oarr.length; x++){
				let orow = oarr[x];
				for(let y=0; y<orow.length; y++){
					narr[y] = narr[y] ? narr[y] : [];
					narr[y][x] = orow[y];
				}
			}
			
			return narr;
		}
		
		// 左右反转 且对齐
		function leftFill(oarr){ 
			// 寻找最大长度
			let xmaxlen = 0;
			for(let x=0; x<oarr.length; x++){
				let len = oarr[x].length;
				xmaxlen = xmaxlen >= len ? xmaxlen : len;
			}
			
			for(let x=0; x<oarr.length; x++){ 
				let orow = oarr[x];
				if(orow.length != xmaxlen){
					for(let y=0; y<xmaxlen; y++){
						if(!orow[y]){
							orow.unshift("N");
						}
					}
				} 
			}
			
			return oarr; 
		}
		
		// 抽取游戏提示信息
		function extractGameTooltip(gameDataMaps){
			let xes = []; 
			let gameDataSize = gameDataMaps.length;
			
			for(let x=0; x<gameDataSize; x++){ 
				xes[x] = [];
				
				let ts = gameDataMaps[x].join("").split("0");
				for(let xx = 0; xx<ts.length; xx++){
					let tslen = ts[xx].length;
					if(tslen > 0){
						xes[x].push(tslen);
					}
				} 
			}  
			
			return leftFill(xes);
		}
		
		// 页面加载完成之后
		function loadPageSuccess(){
			initNonocrams(1); 
		}
	</script>
</head>

<body style="text-align: center; overflow-x:hidden;" onload="loadPageSuccess()" >
 <div class="mainPanel">
	<div class="headPanel">
		<h2>nonograms 数织</h2>
		<div>
		  游戏尺寸: 
		  <input id="gamesize1" name="gamesize" value="1" type="radio" onchange="initNonocrams(this.value)" checked="checked" /><label for="gamesize1">5×5</label>
		  <input id="gamesize2" name="gamesize" value="2" type="radio" onchange="initNonocrams(this.value)"/><label for="gamesize2">10×10</label>
		  <input id="gamesize3" name="gamesize" value="3" type="radio" onchange="initNonocrams(this.value)"/><label for="gamesize3">15×15</label>
		  <input id="gamesize4" name="gamesize" value="4" type="radio" onchange="initNonocrams(this.value)"/><label for="gamesize4">20×20</label>
		  <input id="gamesize5" name="gamesize" value="5" type="radio" onchange="initNonocrams(this.value)"/><label for="gamesize5">25×25</label>
		  <br />
		  游戏设置:
		  <input id="gamemode1" name="gamemode" type="radio" value="RealTime" onchange="alert(1)" checked="checked" /><label for="gamemode1">实时验证</label>
		  &nbsp;&nbsp;
		  <input id="gamemode2" name="gamemode" type="radio" value="Manual" onchange="alert(2)"/><label for="gamemode2">手动验证</label>
		</div>
	</div>
	<div id="gamePanel" class="gamePanel">
		<div id="gameUIPanel" class="gameUIPanel"></div>
	</div>
	<div class="footerPanel">
		<div>游戏规则来自于<a href="https://cn.puzzle-nonograms.com/" target="_blank">puzzle-nonograms</a></div>
	</div>
 </div>
</body>
</html>
